using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Gko.Utils
{
	/// <summary>
	/// Provides methods for manipulating disposable objects.
	/// </summary>
	public static class DisposableUtility
	{
		/// <summary>
		/// Disposes and nulls the specified object.
		/// </summary>
		/// <param name="obj">The object to dispose and null.</param>
		/// <remarks>See <a href="http://code.logos.com/blog/2008/02/disposed_objects.html">Disposed objects</a>.</remarks>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "0#")]
		public static void Dispose<T>(ref T obj) where T : class, IDisposable
		{
			if (obj == null) {
				return;
			}
			obj.Dispose();
			obj = null;
		}

		/// <summary>
		/// Disposes the specified object after executing the specified delegate.
		/// </summary>
		/// <typeparam name="TInput">The type of the input.</typeparam>
		/// <typeparam name="TOutput">The type of the output.</typeparam>
		/// <param name="input">The object to dispose.</param>
		/// <param name="function">The delegate to execute before disposing the object.</param>
		/// <returns>The value returned by the delegate.</returns>
		/// <remarks>See <a href="http://code.logos.com/blog/2008/02/another_extension_method_dispo.html">Another extension method: DisposeAfter</a>.</remarks>
		public static TOutput DisposeAfter<TInput, TOutput>(this TInput input, Func<TInput, TOutput> function)
			where TInput : IDisposable
		{
			using (input) {
				return function(input);
			}
		}

		/// <summary>
		/// Disposes the specified object after executing the specified delegate.
		/// </summary>
		/// <typeparam name="TInput">The type of the input.</typeparam>
		/// <typeparam name="TOutput">The type of the output.</typeparam>
		/// <param name="input">The object to dispose.</param>
		/// <param name="function">The delegate to execute before disposing the object.</param>
		/// <returns>The value returned by the delegate.</returns>
		/// <remarks>See <a href="http://code.logos.com/blog/2008/02/another_extension_method_dispo.html">Another extension method: DisposeAfter</a>.</remarks>
		public static TOutput DisposeAfter<TInput, TOutput>(this TInput input, Func<TOutput> function) where TInput : IDisposable
		{
			using (input) {
				return function();
			}
		}

		/// <summary>
		/// Disposes the specified object after executing the specified delegate.
		/// </summary>
		/// <typeparam name="TInput">The type of the input.</typeparam>
		/// <param name="input">The object to dispose.</param>
		/// <param name="action">The delegate to execute before disposing the object.</param>
		/// <returns>The value returned by the delegate.</returns>
		/// <remarks>See <a href="http://code.logos.com/blog/2008/02/another_extension_method_dispo.html">Another extension method: DisposeAfter</a>.</remarks>
		public static void DisposeAfter<TInput>(this TInput input, Action action) where TInput : IDisposable
		{
			using (input) {
				action();
			}
		}

		/// <summary>
		/// Disposes the specified object after executing the specified delegate.
		/// </summary>
		/// <typeparam name="TInput">The type of the input.</typeparam>
		/// <param name="input">The object to dispose.</param>
		/// <param name="action">The delegate to execute before disposing the object.</param>
		/// <returns>The value returned by the delegate.</returns>
		/// <remarks>See <a href="http://code.logos.com/blog/2008/02/another_extension_method_dispo.html">Another extension method: DisposeAfter</a>.</remarks>
		public static void DisposeAfter<TInput>(this TInput input, Action<TInput> action) where TInput : IDisposable
		{
			using (input) {
				action(input);
			}
		}
	}
}